#ifndef __WRAPPER_SSTRUCTMG_H__
#define __WRAPPER_SSTRUCTMG_H__

typedef int idx_t;
typedef double data_t;

#include "SStructMG.hpp"
#include <chrono>
#include <random>
#include <algorithm>
#include <vector>
#include <string>

class TEST_RECORD {
public:
    double setup = 0.0, solve = 0.0;
    double prec = 0.0, oper = 0.0, axpy = 0.0, dot = 0.0;
    int iter = 0;
    bool operator < (const TEST_RECORD & rec) const {
        double my_tot = setup + solve;
        double his_tot = rec.setup + rec.solve;
        return my_tot < his_tot;
    }
};

struct TEST_CONFIG
{
    int max_iter = 300;
    double atol = 0.0;// 绝对残差
    double rtol = 1.0e-7;// 相对残差
    int iter_print_level = 2;
    int prec_print_level = 1;
    int restart_len = 10;
    int my_nblks = 0;
    std::string config_mg_file;
    SStructGrid<idx_t> * ssgrid_ptr = nullptr;
};

template<typename idx_t>
class PartDescriptor
{
public:
    idx_t id;// 全局块序号
    idx_t ilower[3], iupper[3];
    idx_t nelems;
};

extern IterativeSolver<idx_t, data_t, data_t, data_t> * solver;
extern Solver         <idx_t, data_t, data_t>         * precond;

void buildup_solver(std::string solver_name, std::string prec_name, const TEST_CONFIG & config_file);
void destroy_solver();
void setup_and_solve(const par_SstructMatrix<idx_t, data_t, data_t> & ss_A,
    const par_SstructVector<idx_t, data_t> & b, par_SstructVector<idx_t, data_t> & x,
    TEST_RECORD & record);

void check_residual(const par_SstructMatrix<idx_t, data_t, data_t> & ss_A,
    const par_SstructVector<idx_t, data_t> & ss_x, const par_SstructVector<idx_t, data_t> & ss_b,
    par_SstructVector<idx_t, data_t> & ss_y, double & r_nrm2, double & b_nrm2);
void stat_part_times(TEST_RECORD & record);
void stat_multi_runs(std::vector<TEST_RECORD> & records);

void stat_sstructmg_pattern();

#endif